<template>
  <div class="approval-history">
    <div class="history-header">
      <div class="header-left">
        <h3>审批历史记录</h3>
        <span class="sort-hint">{{ sortOrder === 'desc' ? '（最新优先）' : '（最早优先）' }}</span>
      </div>
      <div class="header-actions">
        <el-tooltip 
          :content="sortOrder === 'desc' ? '当前按时间倒序显示（最新在前）' : '当前按时间正序显示（最早在前）'" 
          placement="top"
        >
          <el-button 
            @click="toggleSortOrder" 
            :type="sortOrder === 'desc' ? 'primary' : 'default'" 
            size="small"
          >
            <Icon :icon="sortOrder === 'desc' ? 'ant-design:sort-descending-outlined' : 'ant-design:sort-ascending-outlined'" />
            {{ sortOrder === 'desc' ? '倒序' : '正序' }}
          </el-button>
        </el-tooltip>
        <el-button @click="refreshHistory" :loading="loading" type="primary" size="small">
          <Icon icon="ant-design:reload-outlined" />
          刷新
        </el-button>
      </div>
    </div>
    
    <div class="history-content">
      <div v-if="loading" class="loading-container">
        <el-skeleton :rows="3" animated />
      </div>
      
      <div v-else-if="displayHistory.length > 0" class="timeline-container">
        <el-timeline>
          <el-timeline-item
            v-for="(record, index) in displayHistory"
            :key="index"
            :timestamp="formatDateTime(record.approvalTime)"
            :type="getTimelineType(record.approvalResult)"
            :color="getTimelineColor(record.approvalResult)"
            :size="getTimelineSize(record.approvalResult)"
          >
            <template #dot>
              <div class="custom-timeline-node" :class="getTimelineNodeClass(record.approvalResult)">
                <Icon :icon="getTimelineNodeIcon(record.approvalResult)" />
              </div>
            </template>
            
            <div class="timeline-item-content">
              <div class="approval-card">
                <div class="approval-header">
                  <div class="approval-title">
                    <Icon :icon="getNodeIcon(record.nodeName)" class="node-icon" />
                    <span class="node-name">{{ record.nodeName || record.taskName || '未知节点' }}</span>
                  </div>
                  <div class="approval-status">
                    <el-tag 
                      :type="getStatusType(record.approvalResult)" 
                      size="small"
                      :effect="getStatusEffect(record.approvalResult)"
                    >
                      {{ getStatusText(record.approvalResult) }}
                    </el-tag>
                  </div>
                </div>
                
                <div class="approval-body">
                  <div class="approval-info-compact">
                    <div class="info-row main-info">
                      <div class="info-item">
                        <Icon icon="ant-design:user-outlined" class="info-icon" />
                        <span class="info-label">审批人：</span>
                        <span class="info-value">{{ record.approver || record.assignee || record.userName || '系统' }}</span>
                      </div>
                      
                      <div class="info-item" v-if="record.approvalTime">
                        <Icon icon="ant-design:clock-circle-outlined" class="info-icon" />
                        <span class="info-label">时间：</span>
                        <span class="info-value">{{ formatDateTime(record.approvalTime) }}</span>
                      </div>
                      
                      <div class="info-item" v-if="record.nextAssignee">
                        <Icon icon="ant-design:user-switch-outlined" class="info-icon" />
                        <span class="info-label">下一步：</span>
                        <span class="info-value">{{ record.nextAssignee }}</span>
                      </div>
                      
                      <div class="info-item" v-if="record.ccUsers">
                        <Icon icon="ant-design:team-outlined" class="info-icon" />
                        <span class="info-label">抄送：</span>
                        <span class="info-value">{{ formatCcUsers(record.ccUsers) }}</span>
                      </div>
                      
                      <div class="info-item" v-if="record.notifyMethods">
                        <Icon icon="ant-design:notification-outlined" class="info-icon" />
                        <span class="info-label">通知：</span>
                        <span class="info-value">{{ formatNotifyMethods(record.notifyMethods) }}</span>
                      </div>
                    </div>
                    
                    <div class="info-row opinion-row" v-if="record.approvalOpinion">
                      <div class="info-item opinion-item">
                        <Icon icon="ant-design:message-outlined" class="info-icon" />
                        <span class="info-label">审批意见：</span>
                        <span class="info-value opinion-text">{{ record.approvalOpinion }}</span>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </el-timeline-item>
        </el-timeline>
      </div>
      
      <div v-else class="empty-history">
        <div class="empty-content">
          <Icon icon="ant-design:inbox-outlined" class="empty-icon" />
          <p class="empty-text">暂无审批记录</p>
          <p class="empty-desc">当前流程还没有审批记录</p>
          <el-button @click="refreshHistory" type="primary" size="small">
            <Icon icon="ant-design:reload-outlined" />
            重新加载
          </el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import Icon from '@/components/Icon/Icon.vue'

// 引入统一的夜间模式样式
import '../styles/dark-theme.css'

const props = defineProps({
  processData: {
    type: Object,
    default: null
  },
  approvalHistory: {
    type: Array,
    default: () => []
  },
  processInstanceId: {
    type: String,
    default: ''
  }
})

const emit = defineEmits(['refresh'])

// 状态管理
const loading = ref(false)
const sortOrder = ref('desc') // 'desc' 倒序（最新在前）, 'asc' 正序（最早在前）

// 计算属性：显示的审批历史
const displayHistory = computed(() => {
  const history = props.approvalHistory || []
  
  // 如果没有数据，直接返回
  if (history.length === 0) {
    return []
  }
  
  // 根据排序顺序返回数据
  if (sortOrder.value === 'desc') {
    // 倒序：最新的在前
    return [...history].sort((a, b) => {
      const timeA = getTimeValue(a.approvalTime)
      const timeB = getTimeValue(b.approvalTime)
      
      // 如果时间相同，按创建时间排序
      if (timeA === timeB) {
        const createTimeA = getTimeValue(a.createTime)
        const createTimeB = getTimeValue(b.createTime)
        return createTimeB - createTimeA
      }
      
      return timeB - timeA
    })
  } else {
    // 正序：最早的在前
    return [...history].sort((a, b) => {
      const timeA = getTimeValue(a.approvalTime)
      const timeB = getTimeValue(b.approvalTime)
      
      // 如果时间相同，按创建时间排序
      if (timeA === timeB) {
        const createTimeA = getTimeValue(a.createTime)
        const createTimeB = getTimeValue(b.createTime)
        return createTimeA - createTimeB
      }
      
      return timeA - timeB
    })
  }
})

// 获取时间值用于排序
const getTimeValue = (dateTime) => {
  if (!dateTime) return 0
  
  try {
    let date
    
    // 处理数组格式的时间 [year, month, day, hour, minute, second]
    if (Array.isArray(dateTime)) {
      if (dateTime.length >= 6) {
        const [year, month, day, hour, minute, second] = dateTime
        date = new Date(year, month - 1, day, hour, minute, second)
      } else {
        return 0
      }
    } else if (typeof dateTime === 'string') {
      if (dateTime.includes('T') || dateTime.includes('Z')) {
        date = new Date(dateTime)
      } else {
        date = new Date(dateTime.replace(/-/g, '/'))
      }
    } else if (dateTime instanceof Date) {
      date = dateTime
    } else {
      date = new Date(dateTime)
    }
    
    return isNaN(date.getTime()) ? 0 : date.getTime()
  } catch (error) {
    return 0
  }
}

// 切换排序顺序
const toggleSortOrder = () => {
  sortOrder.value = sortOrder.value === 'desc' ? 'asc' : 'desc'
}

// 刷新历史
const refreshHistory = () => {
  emit('refresh')
}

// 获取时间线类型
const getTimelineType = (result) => {
  const typeMap = {
    'PASS': 'success',
    'REJECT': 'danger',
    'TRANSFER': 'warning',
    'CC': 'info'
  }
  return typeMap[result] || 'primary'
}

// 获取时间线颜色
const getTimelineColor = (result) => {
  const colorMap = {
    'PASS': '#67c23a', // 通过
    'REJECT': '#f56c6c', // 拒绝
    'TRANSFER': '#e6a23c', // 转办
    'CC': '#909399' // 抄送
  }
  return colorMap[result] || '#409eff' // 默认蓝色
}

// 获取时间线大小
const getTimelineSize = (result) => {
  const sizeMap = {
    'PASS': 'large',
    'REJECT': 'large',
    'TRANSFER': 'large',
    'CC': 'large'
  }
  return sizeMap[result] || 'default'
}

// 获取状态类型
const getStatusType = (result) => {
  const statusMap = {
    'PASS': 'success',
    'REJECT': 'danger',
    'TRANSFER': 'warning',
    'CC': 'info',
    'APPROVED': 'success',
    'REJECTED': 'danger',
    'TRANSFERRED': 'warning'
  }
  return statusMap[result] || 'info'
}

// 获取状态文本
const getStatusText = (result) => {
  const textMap = {
    'PASS': '通过',
    'REJECT': '拒绝',
    'TRANSFER': '转办',
    'CC': '抄送',
    'APPROVED': '已通过',
    'REJECTED': '已拒绝',
    'TRANSFERRED': '已转办'
  }
  return textMap[result] || result
}

// 获取状态效果
const getStatusEffect = (result) => {
  const effectMap = {
    'PASS': 'light',
    'REJECT': 'light',
    'TRANSFER': 'light',
    'CC': 'light'
  }
  return effectMap[result] || 'light'
}

// 获取节点图标
const getNodeIcon = (nodeName) => {
  if (!nodeName) return 'ant-design:swap-outlined'
  
  const nodeNameLower = nodeName.toLowerCase()
  
  // 根据节点名称关键词匹配图标
  if (nodeNameLower.includes('审批') || nodeNameLower.includes('审核')) {
    return 'ant-design:check-circle-outlined'
  } else if (nodeNameLower.includes('会签') || nodeNameLower.includes('并行')) {
    return 'ant-design:team-outlined'
  } else if (nodeNameLower.includes('条件') || nodeNameLower.includes('网关')) {
    return 'ant-design:swap-outlined'
  } else if (nodeNameLower.includes('子流程')) {
    return 'ant-design:apartment-outlined'
  } else if (nodeNameLower.includes('分支')) {
    return 'ant-design:fork-outlined'
  } else if (nodeNameLower.includes('合并')) {
    return 'ant-design:merge-cells-outlined'
  } else if (nodeNameLower.includes('结束')) {
    return 'ant-design:check-circle-outlined'
  } else if (nodeNameLower.includes('开始')) {
    return 'ant-design:play-circle-outlined'
  } else if (nodeNameLower.includes('任务')) {
    return 'ant-design:file-text-outlined'
  } else if (nodeNameLower.includes('部门')) {
    return 'ant-design:apartment-outlined'
  } else if (nodeNameLower.includes('经理') || nodeNameLower.includes('领导')) {
    return 'ant-design:crown-outlined'
  } else if (nodeNameLower.includes('财务')) {
    return 'ant-design:account-book-outlined'
  } else if (nodeNameLower.includes('人事')) {
    return 'ant-design:user-outlined'
  } else if (nodeNameLower.includes('技术')) {
    return 'ant-design:code-outlined'
  } else {
    return 'ant-design:swap-outlined' // 默认图标
  }
}

// 获取时间线节点图标
const getTimelineNodeIcon = (result) => {
  const iconMap = {
    'PASS': 'ant-design:check-circle-outlined',
    'REJECT': 'ant-design:close-circle-outlined',
    'TRANSFER': 'ant-design:swap-outlined',
    'CC': 'ant-design:team-outlined',
    'APPROVED': 'ant-design:check-circle-outlined',
    'REJECTED': 'ant-design:close-circle-outlined',
    'TRANSFERRED': 'ant-design:swap-outlined',
    'PENDING': 'ant-design:clock-circle-outlined',
    'PROCESSING': 'ant-design:sync-outlined'
  }
  return iconMap[result] || 'ant-design:swap-outlined'
}

// 获取时间线节点类
const getTimelineNodeClass = (result) => {
  const classMap = {
    'PASS': 'success',
    'REJECT': 'danger',
    'TRANSFER': 'warning',
    'CC': 'info',
    'APPROVED': 'success',
    'REJECTED': 'danger',
    'TRANSFERRED': 'warning',
    'PENDING': 'info',
    'PROCESSING': 'primary'
  }
  return classMap[result] || 'primary'
}

// 格式化日期时间
const formatDateTime = (dateTime) => {
  if (!dateTime) return '-'
  
  try {
    let date
    
    // 处理数组格式的时间 [year, month, day, hour, minute, second]
    if (Array.isArray(dateTime)) {
      if (dateTime.length >= 6) {
        const [year, month, day, hour, minute, second] = dateTime
        date = new Date(year, month - 1, day, hour, minute, second) // month需要减1，因为Date构造函数中月份是0-11
      } else {
        console.warn('Invalid date array format:', dateTime)
        return '-'
      }
    } else if (typeof dateTime === 'string') {
      // 处理ISO格式的日期字符串
      if (dateTime.includes('T') || dateTime.includes('Z')) {
        date = new Date(dateTime)
      } else {
        // 处理其他格式的日期字符串
        date = new Date(dateTime.replace(/-/g, '/'))
      }
    } else if (dateTime instanceof Date) {
      date = dateTime
    } else {
      // 尝试直接创建Date对象
      date = new Date(dateTime)
    }
    
    // 检查日期是否有效
    if (isNaN(date.getTime())) {
      console.warn('Invalid date:', dateTime)
      return '-'
    }
    
    return date.toLocaleString('zh-CN', {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit'
    })
  } catch (error) {
    console.error('Date formatting error:', error, 'Input:', dateTime)
    return '-'
  }
}

// 格式化抄送用户
const formatCcUsers = (ccUsers) => {
  if (!ccUsers) return '无'
  
  try {
    // 如果是JSON字符串，尝试解析
    if (typeof ccUsers === 'string') {
      if (ccUsers.startsWith('[') && ccUsers.endsWith(']')) {
        const users = JSON.parse(ccUsers)
        return users.join('，')
      } else if (ccUsers.includes(',')) {
        // 如果是逗号分隔的字符串
        return ccUsers.split(',').join('，')
      } else {
        return ccUsers
      }
    } else if (Array.isArray(ccUsers)) {
      return ccUsers.map(user => user.userName || user.name || user).join('，')
    }
    return ccUsers
  } catch (error) {
    return ccUsers || '无'
  }
}

// 格式化通知方式
const formatNotifyMethods = (notifyMethods) => {
  if (!notifyMethods) return '无'
  
  try {
    // 如果是JSON字符串，尝试解析
    if (typeof notifyMethods === 'string') {
      if (notifyMethods.startsWith('[') && notifyMethods.endsWith(']')) {
        const methods = JSON.parse(notifyMethods)
        return methods.join('，')
      } else if (notifyMethods.includes(',')) {
        // 如果是逗号分隔的字符串
        return notifyMethods.split(',').join('，')
      } else {
        return notifyMethods
      }
    } else if (Array.isArray(notifyMethods)) {
      return notifyMethods.join('，')
    }
    return notifyMethods
  } catch (error) {
    return notifyMethods || '无'
  }
}

// 暴露方法给父组件
defineExpose({
  refreshHistory
})
</script>

<style scoped>
.approval-history { padding: 20px 0; }

.history-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.header-left {
  display: flex;
  align-items: center;
  gap: 8px;
}

.history-header h3 {
  margin: 0;
  color: #1a1a1a;
  font-size: 16px;
  font-weight: 600;
}

.sort-hint {
  font-size: 12px;
  color: #909399;
  font-weight: 400;
}

.header-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

.history-content { min-height: 400px; }
.loading-container { padding: 20px; }
.timeline-container { padding: 0 20px; }

.timeline-item-content {
  padding: 6px 0;
  animation: slideInUp 0.3s ease-out;
}

@keyframes slideInUp {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

.approval-card {
  background-color: #f5f7fa;
  border-radius: 6px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
  overflow: hidden;
}

.approval-card:hover {
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
  transform: translateY(-1px);
}

.approval-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  border-bottom: 1px solid #ebeef5;
  background: linear-gradient(135deg, #ecf5ff 0%, #f0f9ff 100%);
  border-radius: 6px 6px 0 0;
  position: relative;
}

.approval-header::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: linear-gradient(90deg, #409eff, #67c23a);
}

.approval-title {
  display: flex;
  align-items: center;
  gap: 6px;
}

.node-icon {
  font-size: 16px;
  color: #409eff;
  transition: all 0.3s ease;
}

.approval-card:hover .node-icon {
  transform: scale(1.1);
  color: #67c23a;
}

.node-name {
  font-weight: 600;
  color: #333;
  font-size: 14px;
  transition: color 0.3s ease;
}

.approval-card:hover .node-name {
  color: #409eff;
}

.approval-status { flex-shrink: 0; }
.approval-body { padding: 12px 15px; }

.approval-info-compact {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.info-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

.info-row.main-info { gap: 8px; }

.info-row.opinion-row {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid #ebeef5;
}

.info-item {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  background-color: #f8f9fa;
  border-radius: 4px;
  border-left: 2px solid #409eff;
  transition: all 0.2s ease;
  font-size: 13px;
}

.info-item:hover {
  background-color: #f0f9ff;
  border-left-color: #67c23a;
}

.info-item.opinion-item {
  background-color: #f6ffed;
  border-left-color: #52c41a;
  flex: 1;
  min-width: 200px;
  padding: 6px 10px;
}

.info-item.opinion-item:hover {
  background-color: #f0f9ff;
}

.info-icon {
  font-size: 14px;
  color: #909399;
  flex-shrink: 0;
}

.info-label {
  font-size: 12px;
  color: #606266;
  font-weight: 500;
  white-space: nowrap;
}

.info-value {
  font-size: 13px;
  color: #303133;
  word-break: break-all;
  line-height: 1.3;
  font-weight: 500;
}

.opinion-text {
  font-style: italic;
  color: #606266;
  background-color: #fff;
  padding: 4px 6px;
  border-radius: 3px;
  border: 1px solid #e8e8e8;
  margin-left: 4px;
}

.empty-history {
  text-align: center;
  color: #999;
  padding: 60px 0;
}

.empty-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.empty-icon {
  font-size: 48px;
  color: #ccc;
  margin-bottom: 16px;
}

.empty-text {
  margin-bottom: 8px;
  font-size: 16px;
  color: #666;
}

.empty-desc {
  font-size: 14px;
  color: #999;
  margin-bottom: 16px;
}

/* 自定义时间线节点样式 */
.custom-timeline-node {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  color: #ffffff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  border: 2px solid #ffffff;
  transition: all 0.3s ease;
}

.custom-timeline-node:hover {
  transform: scale(1.1);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

.custom-timeline-node.success { background-color: #67c23a; }
.custom-timeline-node.danger { background-color: #f56c6c; }
.custom-timeline-node.warning { background-color: #e6a23c; }
.custom-timeline-node.info { background-color: #909399; }
.custom-timeline-node.primary { background-color: #409eff; }

/* 时间线样式优化 */
:deep(.el-timeline) { padding-left: 0; }

:deep(.el-timeline-item__node) {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 600;
  color: #ffffff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  border: 2px solid #ffffff;
  position: relative;
  z-index: 2;
}

:deep(.el-timeline-item__node--primary) { background-color: #409eff; }
:deep(.el-timeline-item__node--success) { background-color: #67c23a; }
:deep(.el-timeline-item__node--warning) { background-color: #e6a23c; }
:deep(.el-timeline-item__node--danger) { background-color: #f56c6c; }
:deep(.el-timeline-item__node--info) { background-color: #909399; }

:deep(.el-timeline-item__timestamp) {
  color: #909399;
  font-size: 11px;
  font-weight: 500;
  margin-top: 4px;
}

:deep(.el-timeline-item__wrapper) { padding-left: 40px; }

:deep(.el-timeline-item__tail) {
  border-left: 2px solid #e4e7ed;
  left: 15px;
  top: 32px;
}

:deep(.el-timeline-item:last-child .el-timeline-item__tail) { display: none; }

/* 夜间模式支持 */
:deep(.dark) .history-header h3 { color: #ffffff; }
:deep(.dark) .header-left .sort-hint { color: #a0a0a0; }
:deep(.dark) .header-actions .el-button {
  border-color: #4d4d4d;
  background-color: #3a3a3a;
  color: #e0e0e0;
}
:deep(.dark) .header-actions .el-button:hover {
  background-color: #4a4a4a;
  border-color: #5a5a5a;
}
:deep(.dark) .header-actions .el-button--primary {
  background-color: #409eff;
  border-color: #409eff;
  color: #ffffff;
}
:deep(.dark) .header-actions .el-button--primary:hover {
  background-color: #66b1ff;
  border-color: #66b1ff;
}

:deep(.dark) .node-name { color: #e0e0e0; }
:deep(.dark) .approval-card {
  background-color: #2d2d2d;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.3);
}
:deep(.dark) .approval-card:hover {
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
}
:deep(.dark) .approval-header {
  background: linear-gradient(135deg, #3d3d3d 0%, #4a4a4a 100%);
  border-bottom: 1px solid #4d4d4d;
}
:deep(.dark) .approval-title .node-icon { color: #67c23a; }
:deep(.dark) .info-item {
  background-color: #3a3a3a;
  border-left-color: #409eff;
}
:deep(.dark) .info-item:hover {
  background-color: #4a4a4a;
  border-left-color: #67c23a;
}
:deep(.dark) .info-item.opinion-item {
  background-color: #2d4d2d;
  border-left-color: #52c41a;
}
:deep(.dark) .info-item.opinion-item:hover { background-color: #3a5a3a; }
:deep(.dark) .info-icon { color: #a0a0a0; }
:deep(.dark) .info-label { color: #a0a0a0; }
:deep(.dark) .info-value { color: #e0e0e0; }
:deep(.dark) .opinion-text {
  color: #a0a0a0;
  background-color: #2a2a2a;
  border: 1px solid #4a4a4a;
}
:deep(.dark) .info-row.opinion-row { border-top-color: #4d4d4d; }
:deep(.dark) .empty-history { color: #666; }
:deep(.dark) .empty-history .empty-icon { color: #555; }
:deep(.dark) .empty-history .empty-text { color: #a0a0a0; }
:deep(.dark) .empty-history .empty-desc { color: #888; }
:deep(.dark) .el-timeline-item__node {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  border-color: #2d2d2d;
}
:deep(.dark) .el-timeline-item__timestamp { color: #a0a0a0; }
:deep(.dark) .el-timeline-item__tail { border-left-color: #4d4d4d; }
:deep(.dark) .custom-timeline-node {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  border-color: #2d2d2d;
}
:deep(.dark) .custom-timeline-node:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
</style> 